


#include "FreeRTOS.h"
#include "task.h"
#include "qelib.h"
#include "tlsf.h"
#include "xuartps_hw.h"
#include "xcoresightpsdcc.h"
#include "xil_printf.h"
#include "project_config.h"



#define CONFIG_DEBUG_UART   0xFE800000  /* coresightpsdcc */
#define CONFIG_USB_UART1    0xFF010000
#define CONFIG_USB_UART0    0xFF000000



static void assert_hook(const char *func, const char *ext, qe_size line)
{
	sys_fatal("Assert: %s %s %d", func, ext, line);
    while (1);
}

static void log_output(const char *buf)
{
	int len = qe_strlen(buf);
	for (int i=0; i<len; i++) {
		//XCoresightPs_DccSendByte(CONFIG_DEBUG_UART, buf[i]);
        XUartPs_SendByte(CONFIG_USB_UART1, buf[i]);
	}
}

static void logger_init()
{
    qe_u8 level;
    qe_u32 features;

    /*
     * There is a bug that when log user dynamic buffer(no QELOG_RECUR) 
     * and memory use freertos allocator, in isr handler we can't call log
     * function, because pvPortMalloc will call vPortEnterCritical, this 
     * function is not interrupt safe, it will check if interrupt occur
     * and do assert
     * 
     * Recommand use QELOG_RECUR
     */

#if (CONFIG_DEBUG_MODE == 1)
    level    = QELOG_DEBUG;
    features = QELOG_DM | QELOG_RECUR | QELOG_LV | QELOG_HMS | QELOG_CL | QELOG_FUNC;
#else
    level    = QELOG_DEBUG;
    features = QELOG_DM | QELOG_RECUR | QELOG_LV | QELOG_HMS | QELOG_CL;
#endif

    qelog_set_default_output(log_output);
    qelog_init(level, features);

    //qelog_domain_set_level("ip", QELOG_DEBUG);
    //qelog_domain_set_level("dns", QELOG_DEBUG);
    qelog_domain_set_level("tcp-ip", QELOG_DEBUG);
    qelog_domain_set_level("tcp-win", QELOG_DEBUG);
    qelog_domain_set_level("udp", QELOG_DEBUG);
    qelog_domain_set_level("dhcp", QELOG_DEBUG);
    qelog_domain_set_level("arp", QELOG_DEBUG);
    qelog_domain_set_level("socket", QELOG_DEBUG);
    qelog_domain_set_level("psu-netif", QELOG_DEBUG);

    qelog_domain_set_level("psu-emac", QELOG_DEBUG);
    qelog_domain_set_level("psu-emac-phy", QELOG_DEBUG);
    qelog_domain_set_level("psu-emac-dma", QELOG_DEBUG);
    qelog_domain_set_level("psu-netif-mem", QELOG_DEBUG);
}

typedef void* (*qemem_malloc_fn)(qe_size size);

#if (CONFIG_MEM_ALLOCATOR_TLSF == 0)
qemem_allocator allocator = {
	.malloc	= pvPortMalloc,
    .calloc = QE_NULL,
    .realloc = QE_NULL,
    .free = vPortFree,
};

static void mem_init(void)
{
    qemem_set_allocator(&allocator);
}

#else

static tlsf_t tlsf;
static char tlsf_heap[CONFIG_TLSF_HEAP_SIZE];
static void *tlsf_adapte_malloc(qe_size size)
{
    void *mem = QE_NULL;
    vTaskSuspendAll();
    mem = tlsf_malloc(tlsf, size);
    xTaskResumeAll();
    return mem;
}

static void *tlsf_adapte_realloc(void *ptr, qe_size size)
{
    void *mem = QE_NULL;
    vTaskSuspendAll();
    mem = tlsf_realloc(tlsf, ptr, size);
    xTaskResumeAll();
    return mem;
}

static void tlsf_adapte_free(void *ptr)
{
    vTaskSuspendAll();
    tlsf_free(tlsf, ptr);
    xTaskResumeAll();
}

static qemem_allocator tlsf_allocator = {
	.malloc  = (qemem_malloc_fn)tlsf_adapte_malloc,
    .free    = tlsf_adapte_free,
    .calloc  = QE_NULL,
    .realloc = tlsf_adapte_realloc,
};

static void mem_init(void)
{
    tlsf = tlsf_create_with_pool(tlsf_heap, sizeof(tlsf_heap));
	qemem_set_allocator(&tlsf_allocator);
}
#endif

int main(void)
{
	mem_init();

    logger_init();

    qe_assert_set_hook(assert_hook);

    sys_notice("");
    sys_notice("Build time %s %s", __DATE__, __TIME__);
    sys_notice("Copyright (C) by Wei.Studio");

    qe_initcall();

    sys_notice("Scheduler Start");
    vTaskStartScheduler();

    sys_warning("System Exit!!!");
    for (;;);
}
